home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 November: Tool Chest / Dev.CD Nov 94.toast / Tool Chest / Development Tools & Languages / Dylan Related / Mindy-1.1 (sources only) / mindy-1.1 / libraries / coll-ext / solist.dylan < prev    next >
Encoding:
Text File  |  1994-06-29  |  5.3 KB  |  146 lines  |  [TEXT/ttxt]

  1. module:     solist
  2. rcs-header:    $Header: solist.dylan,v 1.1 94/06/28 23:06:56 wlott Exp $
  3. author:     Robert Stockton (rgs@cs.cmu.edu)
  4. synopsis:    Provides "self-organizing lists".  These explicit key
  5.         collections provide roughly the semantics of hash tables, but
  6.         use a probabilistic implementation which provides O(n) worst
  7.         case performance but can provide very fast constant time
  8.         access in the best case.
  9.  
  10. //======================================================================
  11. //
  12. // Copyright (c) 1994  Carnegie Mellon University
  13. // All rights reserved.
  14. // 
  15. // Use and copying of this software and preparation of derivative
  16. // works based on this software are permitted, including commercial
  17. // use, provided that the following conditions are observed:
  18. // 
  19. // 1. This copyright notice must be retained in full on any copies
  20. //    and on appropriate parts of any derivative works.
  21. // 2. Documentation (paper or online) accompanying any system that
  22. //    incorporates this software, or any part of it, must acknowledge
  23. //    the contribution of the Gwydion Project at Carnegie Mellon
  24. //    University.
  25. // 
  26. // This software is made available "as is".  Neither the authors nor
  27. // Carnegie Mellon University make any warranty about the software,
  28. // its performance, or its conformity to any specification.
  29. // 
  30. // Bug reports, questions, comments, and suggestions should be sent by
  31. // E-mail to the Internet address "gwydion-bugs@cs.cmu.edu".
  32. //
  33. //======================================================================
  34.  
  35. //======================================================================
  36. // The "Self Organizing List" is a "poor man's hash table".  More precisely,
  37. // <so-list> is a subclass of <mutable-explicit-key-collection> for which
  38. // addition and retrieval are both linear in the worst case, but which use a
  39. // probabilistic strategy which yields nearly constant time in the best case.  
  40. //
  41. // Because they have a very low overhead, self-organizing lists may provide
  42. // better peformance than hash tables in cases where references have a high
  43. // degree of temporal locality.  They may also be useful in situations where
  44. // it is difficult to create a proper hash function.  
  45. //
  46. // Define new so-lists with 
  47. //
  48. //   make(<so-list>, test: test)
  49. //
  50. // Test is expected to be an equality function.  In particular, it is expected
  51. // to satisfy the identity and transitivity requirements described in chapter
  52. // 5.  If not specified, test defaults to \==.  
  53. //======================================================================
  54.  
  55. define class <so-list> (<stretchy-collection>,
  56.             <mutable-explicit-key-collection>)
  57.   slot data :: <list>, init-value: #();
  58.   // slot accessor provides method for standard collection op "key-test"
  59.   slot key-test :: <function>, init-value: \==, init-keyword: test:;
  60. end class;
  61.  
  62. define constant sol-fip-next-state =
  63.   method (list :: <so-list>, state :: <list>) => (result :: <list>);
  64.     tail(state);
  65.   end method;
  66.  
  67. define constant sol-fip-finished-state? =
  68.   method (list :: <so-list>, state :: <list>, limit)
  69.     state == #();
  70.   end method;
  71.  
  72. define constant sol-fip-current-key =
  73.   method (list :: <so-list>, state :: <list>) => (result :: <object>);
  74.     head(head(state));
  75.   end method;
  76.  
  77.  
  78. define constant sol-fip-current-element =
  79.   method (list :: <so-list>, state :: <list>) => (result :: <object>);
  80.     tail(head(state));
  81.   end method;
  82.  
  83. define constant sol-fip-current-element-setter =
  84.   method (value :: <object>,
  85.       list :: <so-list>, state :: <list>) => (result :: <object>);
  86.     tail(head(state)) := value;
  87.   end method;
  88.  
  89. define constant sol-fip-copy-state =
  90.   method (list :: <so-list>, state :: <list>) => (result :: <list>);
  91.     state;
  92.   end method;
  93.  
  94. define method forward-iteration-protocol (table :: <so-list>)
  95.   values(table.data, #f, sol-fip-next-state, sol-fip-finished-state?,
  96.      sol-fip-current-key, sol-fip-current-element,
  97.      sol-fip-current-element-setter, sol-fip-copy-state);
  98. end method forward-iteration-protocol;
  99.  
  100. define constant sol-no-default = pair(#f, #f);
  101.  
  102. define method element(table :: <so-list>, key :: <object>,
  103.               #key default: default = sol-no-default)
  104.   let list :: <list> = table.data;
  105.   let test :: <function> = table.key-test;
  106.  
  107.   block (return)
  108.     let first = head(list);    // depend upon head(#()) being defined
  109.     case
  110.       list == #() =>
  111.     #f;    // fall through
  112.       test(head(first), key) =>
  113.     return(tail(first));
  114.       otherwise =>
  115.     for (prev = list then state,
  116.          state = tail(list) then tail(state),
  117.          until state == #())
  118.       let elem = head(state);
  119.       if (test(head(elem), key))
  120.         tail(prev) := tail(state);
  121.         tail(state) := list;
  122.         table.data := state;
  123.         return(tail(elem));
  124.       end if;
  125.     end for;
  126.     end case;
  127.     // We never reach this point if the element is present.
  128.     if (default == sol-no-default) error("Key %= not in %=", key, table)
  129.     else default
  130.     end if;
  131.   end block;
  132. end method element;
  133.  
  134. define constant sol-no-value = pair(#f, #f);
  135.  
  136. define method element-setter(value, table :: <so-list>, key :: <object>)
  137.   // Bring the existing element (if any) to the front of the list
  138.   if (element(table, key, default: sol-no-value) == sol-no-value)
  139.     // It wasn't there, so add it
  140.     table.data := pair(pair(key, value), table.data);
  141.   else
  142.     // It was there, so change the value of the first element.
  143.     tail(head(table.data)) := value;
  144.   end if;
  145. end method element-setter;
  146.